package com.tomshushu.doc.freedoc.modular.file;

import com.tomshushu.doc.freedoc.core.exception.ServiceException;
import io.minio.*;
import io.minio.errors.MinioException;
import io.minio.http.Method;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class FileService {

    private final MinioClient minioClient;
    private final String bucket;

    public FileService(MinioClient minioClient, @Value("${minio.bucket}") String bucket) {
        this.minioClient = minioClient;
        this.bucket = bucket;
        initBucket();
    }

    private void initBucket() {
        try {
            boolean found = minioClient.bucketExists(BucketExistsArgs.builder()
                    .bucket(bucket)
                    .build());

            if (!found) {
                minioClient.makeBucket(MakeBucketArgs.builder()
                        .bucket(bucket)
                        .build());
            }

            // 设置桶策略为只读访问对象
            String policy = """
            {
                "Version": "2012-10-17",
                "Statement": [
                    {
                        "Effect": "Allow",
                        "Principal": "*",
                        "Action": "s3:GetObject",
                        "Resource": "arn:aws:s3:::%s/*"
                    }
                ]
            }
            """.formatted(bucket);

            minioClient.setBucketPolicy(SetBucketPolicyArgs.builder()
                    .bucket(bucket)
                    .config(policy)
                    .build());
        } catch (Exception e) {
            log.error("MinIO初始化失败: {}", e.getMessage());
            throw new RuntimeException("MinIO初始化失败", e);
        }
    }

    public FileUploadResponse uploadFile(MultipartFile file) {
        try {
            // 1. 验证文件
            if (file == null || file.isEmpty()) {
                throw new ServiceException("上传文件不能为空");
            }

            // 2. 生成唯一文件名
            String originalFilename = file.getOriginalFilename();
            String fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));
            String uniqueFileName = UUID.randomUUID() + fileExtension;

            // 3. 获取内容类型
            String contentType = file.getContentType();
            if (contentType == null) {
                contentType = Files.probeContentType(Paths.get(originalFilename));
                if (contentType == null) {
                    contentType = "application/octet-stream";
                }
            }

            // 4. 上传到MinIO
            minioClient.putObject(PutObjectArgs.builder()
                    .bucket(bucket)
                    .object(uniqueFileName)
                    .contentType(contentType)
                    .stream(file.getInputStream(), file.getSize(), -1)
                    .build());

            // 5. 生成访问URL
            String url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                    .method(Method.GET)
                    .bucket(bucket)
                    .object(uniqueFileName)
//                    .expiry(7, TimeUnit.DAYS) // URL有效期7天
                    .build());

            return new FileUploadResponse(
                    originalFilename,
                    uniqueFileName,
                    url,
                    file.getSize(),
                    contentType
            );

        } catch (MinioException e) {
            log.error("MinIO上传失败: {} ({})", e.getMessage());
            throw new ServiceException("MinIO上传失败: " + e.getMessage());
        } catch (IOException e) {
            log.error("文件IO错误: {}", e.getMessage());
            throw new ServiceException("文件读取错误");
        } catch (Exception e) {
            log.error("上传过程中发生未知错误: {}", e.getMessage(), e);
            throw new ServiceException("上传失败: " + e.getMessage());
        }
    }

    @Data
    @AllArgsConstructor
    public static class FileUploadResponse {
        private String originalName;
        private String storageName;
        private String url;
        private long size;
        private String contentType;
    }
}